<template>
  <div class="dynamic-code-preview">
    <div class="code-form-container">
      <!-- 左侧切换区域 -->
      <div class="left-panel">
        <div class="panel-header">
          <div class="panel-switch">
            <el-button-group>
              <el-button size="small" :type="leftPanelMode === 'form' ? 'primary' : ''" @click="leftPanelMode = 'form'">
                表单配置
              </el-button>
              <el-button size="small" :type="leftPanelMode === 'code' ? 'primary' : ''" @click="leftPanelMode = 'code'">
                组件代码
              </el-button>
            </el-button-group>
          </div>
          <el-button v-if="leftPanelMode === 'code'" size="small" type="primary" @click="refreshComponent">刷新预览</el-button>
        </div>

        <!-- 表单配置区域 -->
        <div v-if="leftPanelMode === 'form'" class="form-config-content">
          <ViewForm
            v-if="designerRules.length > 0"
            :key="formKey"
            v-model:api="formApi"
            :rule="designerRules"
            :option="formOptions"
            :disabled="false"
            @change="handleFormChange"
          />
          <el-empty v-else description="暂无表单配置，请先生成组件代码" />
          <!-- 调试信息显示 -->
          <div v-if="designerRules.length > 0" class="debug-info">
            <details>
              <summary>调试信息</summary>
              <pre>{{ JSON.stringify(formProps, null, 2) }}</pre>
            </details>
          </div>
        </div>

        <!-- 代码显示区域 -->
        <div v-else class="code-content">
          <pre class="code-display">{{ codeData || '暂无代码数据' }}</pre>
        </div>
      </div>

      <!-- 右侧表单预览区域 -->
      <div class="form-panel">
        <div class="panel-header">
          <span class="panel-title">组件预览</span>
          <el-button v-if="componentError" size="small" type="danger" @click="showErrorDetails = !showErrorDetails">
            {{ showErrorDetails ? '隐藏错误' : '查看错误' }}
          </el-button>
        </div>
        <div class="form-content">
          <!-- 错误信息显示 -->
          <div v-if="componentError" class="error-display">
            <div class="error-summary">
              <el-icon class="error-icon"><WarningFilled /></el-icon>
              <span>组件渲染失败</span>
            </div>
            <div v-if="showErrorDetails" class="error-details">
              <pre class="error-pre">{{ componentError }}</pre>
            </div>
          </div>

          <!-- 动态组件渲染区域 -->
          <div v-else-if="dynamicComponent" class="component-wrapper max-w-400px">
            <component :is="dynamicComponent" :key="componentKey" v-bind="formProps" @input="handleFormInput" />
          </div>

          <!-- 等待组件生成 -->
          <div v-else class="component-waiting">
            <el-empty description="等待Vue组件代码生成完成后进行预览" />
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { ElMessage } from 'element-plus'
import { WarningFilled } from '@element-plus/icons-vue'
import { shallowRef, markRaw } from 'vue'
import * as Vue from 'vue'
import viewForm from '@/components/FcDesigner/utils/form'
import uniqueId from '@form-create/utils/lib/unique'
import debounce from '@form-create/utils/lib/debounce'

export default {
  name: 'DynamicCodePreview',
  components: {
    WarningFilled,
    ViewForm: viewForm.$form()
  },
  props: {
    codeData: {
      type: String,
      default: ''
    },
    designerRules: {
      type: Array,
      default: () => []
    }
  },
  emits: ['component-change', 'form-input', 'input'],
  data() {
    return {
      dynamicComponent: null,
      componentError: '',
      componentKey: 0,
      showErrorDetails: false,
      formData: {},
      leftPanelMode: 'code', // 'form' 或 'code'
      formApi: {},
      formProps: {},
      formKey: '',
      formOptions: {
        global: {
          input: {
            // modelEmit: 'blur'
          },
          select: {
            props: {
              clearable: true
            }
          }
        },
        form: {
          labelPosition: 'top',
          size: 'small'
        },
        submitBtn: {
          show: false
        },
        resetBtn: {
          show: false
        }
      }
    }
  },
  watch: {
    codeData: {
      handler(newCode) {
        if (newCode && newCode.trim()) {
          this.compileVueComponent()
        } else {
          this.cleanupDynamicComponent()
        }
      },
      immediate: true
    },
    designerRules: {
      handler(newRules, oldRules) {
        // 避免不必要的更新 - 检查数组长度和引用
        if (newRules === oldRules || (newRules && oldRules && newRules.length === oldRules.length)) {
          return
        }

        if (newRules && newRules.length > 0) {
          this.formKey = uniqueId()
          this.initializeFormData()
        } else {
          this.formProps = {}
          this.formKey = ''
        }
      },
      immediate: true
    }
  },
  beforeUnmount() {
    this.cleanupDynamicComponent()
  },
  methods: {
    // 编译Vue组件
    async compileVueComponent() {
      if (!this.codeData.trim()) {
        this.componentError = '没有Vue组件代码'
        return
      }

      try {
        // 先清理旧组件
        this.cleanupDynamicComponent()

        this.componentError = ''
        console.log('开始编译Vue组件:', this.codeData)

        // 解析Vue单文件组件
        const templateMatch = this.codeData.match(/<template>([\s\S]*?)<\/template>/)
        const scriptMatch = this.codeData.match(/<script[^>]*>([\s\S]*?)<\/script>/)
        const styleMatch = this.codeData.match(/<style[^>]*>([\s\S]*?)<\/style>/)

        if (!templateMatch) {
          throw new Error('未找到template标签')
        }

        const template = templateMatch[1].trim()
        const script = scriptMatch ? scriptMatch[1].trim() : ''
        const style = styleMatch ? styleMatch[1].trim() : ''

        console.log('解析结果:', { template, script, style })

        // 创建组件选项
        let componentOptions = {}

        if (script) {
          // 处理script内容，移除export default
          const scriptContent = script.replace(/export\s+default\s*/, '')

          // 如果script内容是一个对象字面量，直接解析
          if (scriptContent.trim().startsWith('{') && scriptContent.trim().endsWith('}')) {
            try {
              // 使用Function构造器安全地解析对象
              // eslint-disable-next-line no-new-func
              const func = new Function('return ' + scriptContent)
              componentOptions = func()
            } catch (e) {
              console.error('Script解析失败:', e)
              componentOptions = {}
            }
          } else {
            // 如果不是对象字面量，尝试用eval
            try {
              // eslint-disable-next-line no-eval
              componentOptions = eval('(' + scriptContent + ')')
            } catch (e) {
              console.error('Script执行失败:', e)
              componentOptions = {}
            }
          }
        }

        // 检查Vue编译器是否可用
        if (!Vue.compile) {
          throw new Error('Vue编译器不可用，请确保使用完整版Vue')
        }

        // 编译模板
        const render = Vue.compile(template)

        // 创建最终组件
        const componentId = `dynamic-component-${Date.now()}`
        const finalComponent = {
          name: componentOptions.name || 'DynamicPreviewComponent',
          ...componentOptions,
          render,
          __scopeId: style ? `data-v-${componentId}` : undefined,
          // 添加错误边界
          errorCaptured(err, vm, info) {
            console.error('组件运行时错误:', err, info)
            this.componentError = `组件运行时错误: ${err.message}`
            return false
          },
          // 监听表单输入变化
          emits: ['input', 'change'],
          methods: {
            ...componentOptions.methods,
            // 添加表单输入处理
            handleInput(value, field) {
              this.$emit('input', { value, field })
            }
          }
        }

        // 如果有样式，动态添加到页面
        if (style) {
          this.addDynamicStyle(style, componentId, finalComponent.__scopeId)
        }

        // 更新组件key以强制重新渲染
        this.componentKey++
        // 使用 markRaw 标记组件，避免Vue将其转为响应式对象
        this.dynamicComponent = markRaw(finalComponent)

        console.log('组件编译成功:', finalComponent)
        this.$emit('component-change', finalComponent)

        ElMessage.success('组件编译成功')
      } catch (error) {
        console.error('组件编译失败:', error)
        this.componentError = `组件编译失败: ${error.message}`
        this.cleanupDynamicComponent()
        ElMessage.error('组件编译失败')
      }
    },

    // 添加动态样式
    addDynamicStyle(style, componentId, scopeId) {
      const styleId = `dynamic-style-${componentId}`

      // 移除之前的样式
      const existingStyle = document.getElementById(styleId)
      if (existingStyle) {
        existingStyle.remove()
      }

      const styleElement = document.createElement('style')
      styleElement.id = styleId

      // 处理scoped样式
      let processedStyle = style
      if (scopeId) {
        processedStyle = style.replace(/([^{}]+)\{/g, (match, selector) => {
          // 为每个选择器添加scope属性
          const selectors = selector
            .split(',')
            .map((s) => {
              const trimmed = s.trim()
              return `${trimmed}[${scopeId}]`
            })
            .join(', ')
          return `${selectors} {`
        })
      }

      styleElement.textContent = processedStyle
      document.head.appendChild(styleElement)
    },

    // 清理动态组件
    cleanupDynamicComponent() {
      if (this.dynamicComponent) {
        // 清理旧组件
        this.dynamicComponent = null
        this.componentKey++

        // 清理可能的定时器或事件监听器
        this.$nextTick(() => {
          // 强制垃圾回收
          if (window.gc) {
            window.gc()
          }
        })
      }

      // 清理动态样式
      const dynamicStyles = document.querySelectorAll('[id^="dynamic-style-"]')
      dynamicStyles.forEach((style) => style.remove())
    },

    // 刷新组件
    refreshComponent() {
      this.compileVueComponent()
    },

    // 处理表单输入
    handleFormInput(data) {
      console.log('表单输入变化:', data)
      this.formData = { ...this.formData, ...data }
      this.$emit('form-input', data)
    },

    // 初始化表单数据
    initializeFormData() {
      const formData = {}
      this.designerRules.forEach((rule) => {
        if (rule.field) {
          formData[rule.field] = rule.value || ''
        }
      })
      this.formProps = formData
      console.log('初始化表单数据:', formData)
    },

    // 处理表单变化 - 使用防抖避免频繁更新
    handleFormChange: debounce(function (field, value) {
      console.log('表单配置变化:', field, value)

      // 避免不必要的更新
      if (this.formProps[field] === value) {
        return
      }

      this.formProps = { ...this.formProps, [field]: value }
      // 强制重新渲染组件以应用新的 props
      this.componentKey++
      this.$emit('form-input', { field, value })
    }, 100)
  }
}
</script>

<style scoped>
.dynamic-code-preview {
  height: 100%;
  width: 100%;
}

.code-form-container {
  display: flex;
  height: 100%;
  gap: 1px;
  background-color: #f5f5f5;
}

.left-panel,
.form-panel {
  flex: 1;
  background-color: white;
  display: flex;
  flex-direction: column;
  min-height: 0;
}

.panel-switch {
  display: flex;
  align-items: center;
}

.panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 16px;
  border-bottom: 1px solid #e4e7ed;
  background-color: #fafafa;
  flex-shrink: 0;
}

.panel-title {
  font-weight: 600;
  color: #303133;
  font-size: 14px;
}

.code-content,
.form-content,
.form-config-content {
  flex: 1;
  overflow: auto;
  min-height: 0;
}

.form-config-content {
  padding: 16px;
}

.debug-info {
  margin-top: 16px;
  padding: 12px;
  background-color: #f5f7fa;
  border-radius: 4px;
  border: 1px solid #e4e7ed;
}

.debug-info details {
  cursor: pointer;
}

.debug-info summary {
  font-weight: 600;
  color: #606266;
  margin-bottom: 8px;
}

.debug-info pre {
  margin: 0;
  font-size: 12px;
  color: #303133;
  background-color: #fff;
  padding: 8px;
  border-radius: 4px;
  border: 1px solid #dcdfe6;
  max-height: 200px;
  overflow: auto;
}

.code-display {
  margin: 0;
  padding: 16px;
  background-color: #f8f9fa;
  color: #333;
  font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
  font-size: 12px;
  line-height: 1.5;
  white-space: pre-wrap;
  word-break: break-all;
  min-height: 100%;
  box-sizing: border-box;
}

.form-content {
  padding: 16px;
}

.error-display {
  color: #f56c6c;
}

.error-summary {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 12px;
  font-weight: 600;
}

.error-icon {
  font-size: 18px;
}

.error-details {
  background-color: #fef0f0;
  border: 1px solid #fbc4c4;
  border-radius: 4px;
  padding: 12px;
}

.error-pre {
  margin: 0;
  font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
  font-size: 12px;
  line-height: 1.5;
  white-space: pre-wrap;
  word-break: break-all;
}

.component-wrapper {
  border: 1px solid #e4e7ed;
  border-radius: 4px;
  padding: 16px;
  min-height: 200px;
}

.component-wrapper > * {
  max-width: 100%;
}

.component-wrapper {
  isolation: isolate;
}

.component-waiting {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 200px;
}
</style>
